﻿using System;
using System.Collections.Generic;
using System.Linq;
using DotNetCommon.Extensions;
using DotNetCommon.Logger;
using System.Reflection;
using System.Text.Json;
using System.Linq.Expressions;
using System.Text.Json.Nodes;
using System.Collections;

namespace DotNetCommon.Extensions;

/// <summary>
/// 通用对象扩展方法
/// </summary>
public static class ObjectExtensions
{
    private static readonly ILogger logger = LoggerFactory.CreateLogger("DotNetCommon.Extensions.ObjectExtensions");

    private static readonly TimeSpan timeSpan = TimeSpan.FromHours(8);
    static ObjectExtensions()
    {
        var now = DateTime.Now;
        var utcNow = now.ToUniversalTime();
        timeSpan = now - utcNow;
    }

    #region 私有方法,使用Convert类进行转换
    private static List<TypeCode> _baseTypes = new()
    {
        TypeCode.Byte,TypeCode.SByte,
        TypeCode.Int16,TypeCode.UInt16,
        TypeCode.Int32,TypeCode.UInt32,
        TypeCode.Int64,TypeCode.UInt64,
        TypeCode.Single,TypeCode.Double,TypeCode.Decimal,
        TypeCode.Char,TypeCode.Boolean,TypeCode.String,TypeCode.DateTime
    };

    private static object _baseConvert(TypeCode typeCode, object value)
    {
        switch (typeCode)
        {
            case TypeCode.Byte:
                {
                    return Convert.ToByte(value);
                }
            case TypeCode.SByte:
                {
                    return Convert.ToSByte(value);
                }
            case TypeCode.Int16:
                {
                    return Convert.ToInt16(value);
                }
            case TypeCode.UInt16:
                {
                    return Convert.ToUInt16(value);
                }
            case TypeCode.Int32:
                {
                    return Convert.ToInt32(value);
                }
            case TypeCode.UInt32:
                {
                    return Convert.ToUInt32(value);
                }
            case TypeCode.Int64:
                {
                    return Convert.ToInt64(value);
                }
            case TypeCode.UInt64:
                {
                    return Convert.ToUInt64(value);
                }
            case TypeCode.Single:
                {
                    return Convert.ToSingle(value);
                }
            case TypeCode.Double:
                {
                    return Convert.ToDouble(value);
                }
            case TypeCode.Decimal:
                {
                    return Convert.ToDecimal(value);
                }
            case TypeCode.Char:
                {
                    return Convert.ToChar(value);
                }
            case TypeCode.Boolean:
                {
                    return Convert.ToBoolean(value);
                }
            case TypeCode.String:
                {
                    return Convert.ToString(value);
                }
            case TypeCode.DateTime:
                {
                    return Convert.ToDateTime(value);
                }
            default:
                {
                    return null;
                }
        }
    }
    #endregion

    #region 通用转换方法 object.To<T>()
    private static Func<string, Type, object> _getNewtonsoftJsonDeSerialize = null;
    private static Func<string, Type, object> getNewtonsoftJsonDeSerialize(Assembly assembly)
    {
        if (_getNewtonsoftJsonDeSerialize == null)
        {
            var tmp = assembly.GetType("Newtonsoft.Json.JsonConvert");
            var method = tmp.GetMethods().FirstOrDefault(i => i.Name == "DeserializeObject" && i.GetParameters().Length == 2 && i.GetParameters().LastOrDefault().ParameterType == typeof(Type));
            var para = Expression.Parameter(typeof(string), "str");
            var para2 = Expression.Parameter(typeof(Type), "type");

            _getNewtonsoftJsonDeSerialize = Expression.Lambda<Func<string, Type, object>>(Expression.Block(
                Expression.Call(null, method, para, para2))
                , [para, para2]
                ).Compile();
        }
        return _getNewtonsoftJsonDeSerialize;
    }

    /// <summary>
    /// 通用转换方法
    /// </summary>
    /// <param name="value">待转换对象</param>
    /// <param name="parameters">转换时用到的参数,目前仅用于string -> DateTime/DateTimeOffset</param>
    public static T To<T>(this object value, params object[] parameters)
    {
        if (value is T t) return t;
        Type type = typeof(T);
        if (value == null || value is DBNull)
        {
            //引用类型: 返回默认 即: null
            if (!type.IsValueType) return default;
            //可空类型: 返回默认 即: null
            if (type.IsNullable()) return default;
            //null => int 只能报错
            throw new Exception($"无法将 null 或 dbnull 转为:[{type.GetClassFullName()}]类型!");
        }
        return (T)To(value, type, parameters);
    }

    /// <summary>
    /// 通用转换方法
    /// </summary>
    /// <param name="value">待转换对象</param>
    /// <param name="type">目的类型</param>
    /// <param name="parameters">转换时用到的参数,目前仅用于string -> DateTime/DateTimeOffset</param>
    /// <returns></returns>
    public static object To(this object value, Type type, params object[] parameters)
    {
        //null -> 其他,DBNull -> 其他 (DataTable中使用)
        if (value == null || value is DBNull)
        {
            //引用类型: 返回默认 即: null
            if (!type.IsValueType) return null;
            //可空类型: 返回默认 即: null
            //注意: typeof(int?).IsValueType 结果是 true
            if (type.IsNullable()) return null;
            //null => int 只能报错
            throw new Exception($"无法将 null 或 dbnull 转为:[{type.GetClassFullName()}]类型!");
        }

        //子类 -> 父类
        if (type.IsAssignableFrom(value.GetType())) return value;

        //剥去 int? 的问号
        var oldType = type;
        if (type.IsNullable()) type = type.GenericTypeArguments[0];

        //字符串等转枚举(高频, 高先级)
        if (type.IsEnum) return ConvertToEnum(type, oldType, value);

        //两类型间的转换
        var idx = ConvertBetweenFunc.FindIndex(i => i.srcType == value.GetType() && i.destType == type);
        if (idx >= 0) return ConvertBetweenFunc[idx].func(value, parameters);

        //其他 -> string
        //因为上面 ConvertBetweenFunc 不能考虑所有 Type => string, 所以这里补充一下
        if (type == typeof(string)) return value?.ToString();

        #region 从 JsonNode 等类型转其他
        if (value is JsonElement element)
        {
            // "1".ToObject<object>().To<int>()
            return JsonSerializer.Deserialize(element, type, JsonHelper._getDefaultJsonSerializerOptions());
        }
        else if (value is JsonNode node)
        {
            return JsonSerializer.Deserialize(node, type, JsonHelper._getDefaultJsonSerializerOptions());
        }
        else if (value is JsonDocument document)
        {
            return JsonSerializer.Deserialize(document, type, JsonHelper._getDefaultJsonSerializerOptions());
        }
        #endregion

        #region 兼容 Newtonsoft
        //兼容 Newtonsoft
        var toFullName = type.FullName;
        var fromFullName = value.GetType().FullName;
        if (fromFullName.StartsWith("Newtonsoft.Json."))
        {
            var newtonsoft_serialize = GetNewtonsoftJsonSerialize(value.GetType().Assembly);
            var newtonsoft_de_serialize = getNewtonsoftJsonDeSerialize(value.GetType().Assembly);
            var newtonsoft_serialize2 = getNewtonsoftJsonSerialize3(value.GetType().Assembly);
            var isJValue = fromFullName == "Newtonsoft.Json.Linq.JValue";
            if (isJValue)
            {
                //如下只能采用下面的转换
                //var obj = Newtonsoft.Json.JsonConvert.DeserializeObject<JObject > ("{\"Time\":\"2024-02-01 12:02:03\"}");
                //obj["Time"].ToObject(typeof(DateTime))
                return newtonsoft_serialize2(value, type);
            }
            //如: object/string/Newtonsoft => JObject
            if (toFullName.StartsWith("Newtonsoft.Json."))
            {
                // Newtonsoft => Newtonsoft
                return newtonsoft_de_serialize(newtonsoft_serialize(value).ToString(), type);
            }
            else
            {
                // Newtonsoft => other int/class...
                return JsonSerializer.Deserialize(newtonsoft_serialize(value).ToString(), type);
            }
        }
        else if (toFullName.StartsWith("Newtonsoft.Json."))
        {
            var newtonsoft_serialize = GetNewtonsoftJsonSerialize(type.Assembly);
            var newtonsoft_de_serialize = getNewtonsoftJsonDeSerialize(type.Assembly);
            //如: string/JToken => JObject
            if (fromFullName.StartsWith("Newtonsoft.Json."))
            {
                // Newtonsoft => Newtonsoft
                return newtonsoft_de_serialize(newtonsoft_serialize(value).ToString(), type);
            }
            else
            {
                // string => Newtonsoft
                if (value is string) return newtonsoft_de_serialize(value.ToString(), type);
                else return newtonsoft_de_serialize(JsonSerializer.Serialize(value), type);
            }
        }
        #endregion        

        if (type.IsValueType)
        {
            //值类型
            //可以使用Convert.ToXXX的转换
            var typeCode = type.GetTypeCode();
            if (_baseTypes.Contains(typeCode)) return _baseConvert(typeCode, value);

            //其他 使用 JsonSerializer 实现
            return JsonSerializer.Deserialize(JsonSerializer.Serialize(value), type);
        }
        else
        {
            //兼容从json字符串反序列化
            if (value is string && type.IsClass) return JsonSerializer.Deserialize(value.ToString(), type);
            //引用类型
            return value;
        }
    }

    private static List<(Type srcType, Type destType, Func<object, object[], object> func)> ConvertBetweenFunc =
    [
        #region string => other
		(typeof(string),typeof(bool), (object value, object[] parameters) =>
        {
            var tmp = value.ToString().ToUpper();
            if (new string[] { "OK", "YES", "TRUE", "1", "是" }.Contains(tmp)) return true;
            else return false;
        }),

        (typeof(string),typeof(Guid), (object value, object[] parameters) =>
        {
            return Guid.Parse(value.ToString());
        }),

        (typeof(string),typeof(DateTime), (object value, object[] parameters) =>
        {
            if (parameters != null && parameters.Length > 0)
            {
                return DateTime.ParseExact(value.ToString(), parameters[0].ToString(), null);
            }
            else
            {
                return DateTime.Parse(value.ToString());
            }
        }),
        (typeof(string),typeof(DateTimeOffset), (object value, object[] parameters) =>
        {
            if (parameters != null && parameters.Length > 0)
            {
                return DateTimeOffset.ParseExact(value.ToString(), parameters[0].ToString(), null);
            }
            else
            {
                return DateTimeOffset.Parse(value.ToString());
            }
        }),
        (typeof(string),typeof(DateOnly), (object value, object[] parameters) =>
        {
            if (parameters != null && parameters.Length > 0)
            {
                return DateOnly.ParseExact(value.ToString(), parameters[0].ToString(), null);
            }
            else
            {
                return DateOnly.Parse(value.ToString());
            }
        }),
        (typeof(string),typeof(TimeOnly), (object value, object[] parameters) =>
        {
            if (parameters != null && parameters.Length > 0)
            {
                return TimeOnly.ParseExact(value.ToString(), parameters[0].ToString(), null);
            }
            else
            {
                return TimeOnly.Parse(value.ToString());
            }
        }),
         (typeof(string),typeof(TimeSpan), (object value, object[] parameters) =>
        {
            if (parameters != null && parameters.Length > 0)
            {
                return TimeSpan.ParseExact(value.ToString(), parameters[0].ToString(), null);
            }
            else
            {
                return TimeSpan.Parse(value.ToString());
            }
        }),
	    #endregion

        #region 时间日期互相转换 DateTime DateTimeOffset DateOnly TimeOnly TimeSpan
		#region other => DateOnly
		(typeof(DateTime),typeof(DateOnly), (object value, object[] parameters) =>
        {
            return DateOnly.FromDateTime((DateTime)value);
        }),
        (typeof(DateTimeOffset),typeof(DateOnly), (object value, object[] parameters) =>
        {
            return DateOnly.FromDateTime(((DateTimeOffset)value).DateTime);
        }),
        (typeof(TimeSpan),typeof(DateOnly), (object value, object[] parameters) =>
        {
            throw new Exception("无法从TimeSpan转到DateOnly!");
        }), 
	    #endregion

        #region other => TimeOnly
		(typeof(DateTime),typeof(TimeOnly), (object value, object[] parameters) =>
        {
            return TimeOnly.FromDateTime((DateTime)value);
        }),
        (typeof(DateTimeOffset),typeof(TimeOnly), (object value, object[] parameters) =>
        {
            return TimeOnly.FromDateTime(((DateTimeOffset)value).DateTime);
        }),
        (typeof(TimeSpan),typeof(TimeOnly), (object value, object[] parameters) =>
        {
            return TimeOnly.FromTimeSpan((TimeSpan)value);
        }), 
	    #endregion

        #region other => DateTime
		(typeof(DateOnly),typeof(DateTime), (object value, object[] parameters) =>
        {
            var dateOnly = (DateOnly)value;
            return new DateTime(dateOnly.Year, dateOnly.Month, dateOnly.Day);
        }),
        (typeof(TimeOnly),typeof(DateTime), (object value, object[] parameters) =>
        {
            var timeOnly = (TimeOnly)value;
            return new DateTime(1970, 1, 1, timeOnly.Hour, timeOnly.Minute, timeOnly.Second, timeOnly.Millisecond);
        }), 
	    #endregion

        #region other => DateTimeOffset
		(typeof(DateOnly),typeof(DateTimeOffset), (object value, object[] parameters) =>
        {
            var dateOnly = (DateOnly)value;
            return new DateTimeOffset(dateOnly.Year, dateOnly.Month, dateOnly.Day, 0, 0, 0, timeSpan);
        }),
        (typeof(TimeOnly),typeof(DateTimeOffset), (object value, object[] parameters) =>
        {
            var timeOnly = (TimeOnly)value;
            return new DateTimeOffset(1970, 1, 1, timeOnly.Hour, timeOnly.Minute, timeOnly.Second, timeOnly.Millisecond, timeSpan);
        }), 
	    #endregion

        #region other => TimeSpan
		(typeof(DateOnly),typeof(TimeSpan), (object value, object[] parameters) =>
        {
            var dateOnly = (DateOnly)value;
            throw new Exception("无法从 DateOnly 转到TimeSpan!");
        }),
        (typeof(TimeOnly),typeof(TimeSpan), (object value, object[] parameters) =>
        {
            var timeOnly = (TimeOnly)value;
            return new TimeSpan(0, timeOnly.Hour, timeOnly.Minute, timeOnly.Second, timeOnly.Millisecond);
        }), 
	    #endregion

        #region DateTimeOffset => DateTime
		(typeof(DateTimeOffset),typeof(DateTime), (object value, object[] parameters) =>
        {
            return ((DateTimeOffset)value).DateTime;
        }), 
	    #endregion

        #region TimeSpan => DateTime
		(typeof(TimeSpan),typeof(DateTime), (object value, object[] parameters) =>
        {
            var time = (TimeSpan)value;
            return new DateTime(1970, 01, 01, time.Hours, time.Minutes, time.Seconds, time.Milliseconds);
        }), 
	    #endregion

        #region TimeSpan => DateTimeOffset
		(typeof(TimeSpan),typeof(DateTimeOffset), (object value, object[] parameters) =>
        {
            var time = (TimeSpan)value;
            return new DateTimeOffset(1970, 01, 01, time.Hours, time.Minutes, time.Seconds, time.Milliseconds, timeSpan);
        }), 
	    #endregion         
	    #endregion

        #region other => string
		(typeof(DateTime),typeof(string), (object value, object[] parameters) =>
        {
            var dt = (DateTime)value;
            if (parameters.IsNotNullOrEmpty())
            {
                return dt.ToString(parameters[0].ToString());
            }
            return dt.ToString();
        }),
        (typeof(DateTimeOffset),typeof(string), (object value, object[] parameters) =>
        {
            var offset = (DateTimeOffset)value;
            if (parameters.IsNotNullOrEmpty())
            {
                return offset.ToString(parameters[0].ToString());
            }
            return offset.ToString();
        }),
        (typeof(DateOnly),typeof(string), (object value, object[] parameters) =>
        {
            var dateOnly = (DateOnly)value;
            if (parameters.IsNotNullOrEmpty())
            {
                return dateOnly.ToString(parameters[0].ToString());
            }
            return dateOnly.ToString();
        }),
        (typeof(TimeOnly),typeof(string), (object value, object[] parameters) =>
        {
            var timeOnly = (TimeOnly)value;
            if (parameters.IsNotNullOrEmpty())
            {
                return timeOnly.ToString(parameters[0].ToString());
            }
            return timeOnly.ToString();
        }),
        (typeof(Guid),typeof(string), (object value, object[] parameters) =>
        {
            var guid = (Guid)value;
            if (parameters.IsNotNullOrEmpty())
            {
                return guid.ToString(parameters[0].ToString());
            }
            return guid.ToString();
        }), 
	    #endregion
    ];

    internal static object ConvertToEnum(Type type, Type oldType, object value)
    {
        if (value is null)
        {
            if (oldType.GetType().IsNullable()) return null;
            throw new Exception($"无法将 null 转为 {oldType.GetType().GetClassFullName()}");
        }
        if (value is not string ss)
        {
            var srcType = value.GetType();
            if (srcType.IsArray || typeof(IEnumerable).IsParentOrAssignableFrom(srcType)) ss = value.ToJson();
            else ss = value.ToString();
        }
        //枚举转换
        //假设目标枚举: [Flags]EnumState { Open = 1, Close = 2, Active = 4 }
        //可以转换 "close", "open,close","1" 甚至不存在的数字字符串, 如: "9","-1"
        if (Enum.TryParse(type, ss, true, out var res)) return res;
        if (ss.TrimStart().StartsWith('['))
        {
            //如: ["open","close"],[1,2],["1","2"]
            var arr = JsonArray.Parse(ss).AsArray();
            if (arr.Count == 0)
            {
                //如: []
                if (oldType.IsNullable()) return null;
            }
            else
            {
                //将数组转成字符串
                //["open","close"] => "open,close"
                //[1,2] => "1,2"
                //["1","2"] => "1,2"
                ss = arr.ToStringSeparated(",");
                //再尝试转一次
                if (Enum.TryParse(type, ss, true, out var res2)) return res2;

                //强制按数字转
                var num = ss.Split(',').Select(i => int.Parse(i)).Aggregate((i, j) => i | j);
                //(EnumState?)2 会报错
                if (oldType.IsNullable()) return Enum.Parse(type, num.ToString());
                return num;
            }
        }
        else if (ss.Contains(','))
        {
            //如: "1,2"
            //强制按数字转
            var num = ss.Split(',').Select(i => int.Parse(i)).Aggregate((i, j) => i | j);
            //(EnumState?)2 会报错
            if (oldType.IsNullable()) return Enum.Parse(type, num.ToString());
            return num;
        }
        if (oldType.IsNullable()) return null;
        throw new Exception($"无法将 {value} 转为枚举[{oldType.GetClassFullName()}]!");
    }

    private static readonly MethodInfo m_To = typeof(ObjectExtensions).GetMethod("To", [typeof(object), typeof(Type), typeof(object[])]);
    /// <summary>
    /// 获取类型转换表达式, 如:
    /// <list type="bullet">
    /// <item>GetConvertExpr(typeof(int), typeof(int), srcInstExpr) => srcInstExpr</item>
    /// <item>GetConvertExpr(typeof(long?), typeof(int), srcInstExpr) => val==null?throw new NotImplementedException(): (int)((long)val)</item>
    /// </list>
    /// </summary>
    public static Expression GetConvertExpr(Expression srcInstExpr, Type destType, object[] parameters = null)
    {
        AssertUtil.NotNull(destType);
        AssertUtil.NotNull(srcInstExpr);

        var srcType = srcInstExpr.Type;
        //同类型 直接返回
        if (srcType == destType) return srcInstExpr;

        //继承关系
        if (destType.IsParentOrAssignableFrom(srcType)) return Expression.Convert(srcInstExpr, destType);

        //剥去 int? 的问号
        var oldDestType = destType;
        if (destType.IsNullable()) destType = destType.GenericTypeArguments[0];

        var oldSrcType = srcType;
        if (srcType.IsNullable()) srcType = srcType.GenericTypeArguments[0];

        //如果去掉 NullAble<> 影响后刚好相同的话, 则认为是: int<=>int? 直接转即可
        if (srcType == destType) return Expression.Convert(srcInstExpr, oldDestType);

        //其他转枚举
        if (destType.IsEnum)
        {
            return Expression.Convert
                (
                    Expression.Call(typeof(ObjectExtensions).GetMethod(nameof(ConvertToEnum), BindingFlags.NonPublic | BindingFlags.Static), [Expression.Constant(destType), Expression.Constant(oldDestType), Expression.Convert(srcInstExpr, typeof(object))]),
                    oldDestType
                );
        }

        var isSrcRef = !oldSrcType.IsValueType || oldSrcType.IsNullable();
        var isDestRef = !oldDestType.IsValueType || oldDestType.IsNullable();

        //先看有没有直接支持两类型间转换的
        var idx = ConvertBetweenFunc.FindIndex(i => i.srcType == srcType && i.destType == destType);
        //两类型间的转换
        if (idx >= 0)
        {
            //expr_func: (value, paramenters) => ConvertBetweenFunc[idx].func(value, parameters)
            Expression<Func<object, object[], object>> expr = (object value, object[] parameters) => ConvertBetweenFunc[idx].func(value, parameters);
            return Expression.Convert(Expression.Invoke(expr, Expression.Convert(srcInstExpr, typeof(object)), Expression.Constant(parameters, typeof(object[]))), oldDestType);
        }

        //其他 -> string
        if (destType == typeof(string))
        {
            var m_ToString = oldSrcType.GetMethods().First(i => i.Name == "ToString" && i.GetParameters().Length == 0);
            var cvt = Expression.Call(srcInstExpr, m_ToString, []);

            if (isSrcRef)
            {
                return Expression.Condition(Expression.Equal(srcInstExpr, Expression.Constant(null)), Expression.Constant(null, typeof(string)), cvt);
            }
            else
            {
                return cvt;
            }
        }

        //long -> int
        var destTypeCode = destType.GetTypeCode();
        if (_dicTypeCodeNames.TryGetValue(destTypeCode, out var name))
        {
            var cvt = Expression.Convert(Expression.Call(null, typeof(Convert).GetMethods().First(i => i.Name == name && i.GetParameters().Length == 1 && i.GetParameters()[0].ParameterType == typeof(object)), [Expression.Convert(srcInstExpr, typeof(object))]), oldDestType);
            if (isSrcRef)
            {
                return Expression.Condition(Expression.Equal(srcInstExpr, Expression.Constant(null)),
                    isDestRef ? Expression.Constant(null) : Expression.Throw(Expression.Constant(new Exception($"无法将 null 转为: {oldDestType.GetClassFullName()}")), oldDestType),
                    cvt);
            }
            else
            {
                return cvt;
            }
        }

        //return (int?)src.To((object)src, int, parameters)
        return Expression.Convert(Expression.Call(null, m_To, Expression.Convert(srcInstExpr, typeof(object)), Expression.Constant(destType), Expression.Constant(parameters, typeof(object[]))), oldDestType);
    }

    private static readonly Dictionary<TypeCode, string> _dicTypeCodeNames = new()
    {
        {TypeCode.Byte, nameof(Convert.ToByte)},
        {TypeCode.SByte, nameof(Convert.ToSByte)},
        {TypeCode.Int16, nameof(Convert.ToInt16)},
        {TypeCode.UInt16, nameof(Convert.ToUInt16)},
        {TypeCode.Int32, nameof(Convert.ToInt32)},
        {TypeCode.UInt32, nameof(Convert.ToUInt32)},
        {TypeCode.Int64, nameof(Convert.ToInt64)},
        {TypeCode.UInt64, nameof(Convert.ToUInt64)},
        {TypeCode.Single, nameof(Convert.ToSingle)},
        {TypeCode.Double, nameof(Convert.ToDouble)},
        {TypeCode.Decimal, nameof(Convert.ToDecimal)},
        {TypeCode.Char, nameof(Convert.ToChar)},
        {TypeCode.Boolean, nameof(Convert.ToBoolean)},
        {TypeCode.String, nameof(Convert.ToString)},
        {TypeCode.DateTime, nameof(Convert.ToDateTime)},
    };

    /// <summary>
    /// 通用转换方法
    /// </summary>
    public static T ToWithDefault<T>(this object value, T defaultValue, params object[] parameters)
    {
        if (value is T) return (T)value;
        Type type = typeof(T);
        if (value == null || value is DBNull)
        {
            //引用类型: 返回默认 即: null
            if (!type.IsValueType) return default;
            //可空类型: 返回默认 即: null
            if (type.IsNullable()) return default;
        }
        return (T)ToWithDefault(value, type, defaultValue, parameters);
    }

    /// <summary>
    /// 通用转换方法
    /// </summary>
    public static object ToWithDefault(this object value, Type type, object defaultValue, params object[] parameters)
    {
        if (type == null) return defaultValue;
        if (value == null || value is DBNull)
        {
            //引用类型: 返回默认 即: null
            if (!type.IsValueType) return null;
            //可空类型: 返回默认 即: null
            if (type.IsNullable()) return null;
        }

        try
        {
            return value.To(type, parameters);
        }
        catch
        {
            logger.LogWarning($"ToWithDefault触发异常[{value} => {type.FullName}],注意频繁异常会降低程序性能.");
            return defaultValue;
        }
    }
    #endregion

    #region 基于同名属性的对象映射 object.Mapper<TResult>()
    /// <summary>
    /// 对象映射，基于同名属性转换原则<br />
    /// 调用方法:
    /// <br />
    /// var person=new Person();<br />
    /// var dto=person.Mapper&lt;PersonDto>();<br />
    /// var persons=new List&lt;Person>();<br />
    /// var dtos=persons.Mapper&lt;List&lt;PersonDto>>();<br />
    /// </summary>
    /// <typeparam name="TResult">目标类型</typeparam>
    /// <param name="src">原实例</param>
    /// <param name="containsRepeatReference">是否考虑引用关系</param>
    /// <param name="null2Default">是否将null值转换为默认值,而不是抛出异常</param>
    /// <returns></returns>
    public static TResult Mapper<TResult>(this object src, bool containsRepeatReference = true, bool null2Default = true)
    {
        var destType = typeof(TResult);
        if (src.IsNullOrDBNull())
        {
            if (null2Default || !destType.IsValueType || destType.IsNullable()) return default;
            throw new Exception($"无法从 null or dbnull 转换为 {destType.GetClassFullName()}");
        }
        var srcType = src.GetType();

        if (srcType == destType) return (TResult)src;
        return (TResult)MapperHelper.Mapper(srcType, destType, src, containsRepeatReference, null2Default);
    }

    /// <summary>
    /// 对象映射，基于同名属性转换原则<br />
    /// 调用方法:
    /// <br />
    /// var person=new Person();<br />
    /// var dto=person.Mapper&lt;Person,PersonDto>();<br />
    /// var persons=new List&lt;Person>();<br />
    /// var dtos=persons.Mapper&lt;List&lt;Person>,List&lt;PersonDto>>();<br />
    /// </summary>
    /// <typeparam name="TFrom">源类型</typeparam>
    /// <typeparam name="TDest">目标类型</typeparam>
    /// <param name="src"></param>
    /// <param name="containsRepeatReference">是否考虑引用关系</param>
    /// <param name="null2Default">是否将null值转换为默认值,而不是抛出异常</param>
    /// <remarks>
    /// 注意：相对于 <c>person.Mapper&lt;PersonDto>()</c> 增加指定源目标类型
    /// </remarks>
    /// <returns></returns>
    public static TDest Mapper<TFrom, TDest>(this object src, bool containsRepeatReference = true, bool null2Default = true)
    {
        var destType = typeof(TDest);
        if (src.IsNullOrDBNull())
        {
            if (null2Default || !destType.IsValueType || destType.IsNullable()) return default;
            throw new Exception($"无法从 null or dbnull 转换为 {destType.GetClassFullName()}");
        }
        var srcType = typeof(TFrom);
        if (srcType == destType) return (TDest)src;
        return (TDest)MapperHelper.Mapper(srcType, destType, src, containsRepeatReference, null2Default);
    }

    /// <summary>
    /// 对象映射，基于同名属性转换原则<br />
    /// 调用方法:
    /// <br />
    /// var person=new Person();<br />
    /// var dto=person.Mapper(typeof(PersonDto));<br />
    /// var persons=new List&lt;Person>();<br />
    /// var dtos=persons.Mapper(typeof(List&lt;PersonDto>));<br />
    /// </summary>
    /// <param name="src"></param>
    /// <param name="type">目标类型</param>
    /// <param name="containsRepeatReference">是否考虑引用关系</param>
    /// <param name="null2Default">是否将null值转换为默认值,而不是抛出异常</param>
    /// <returns></returns>
    public static object Mapper(this object src, Type type, bool containsRepeatReference = true, bool null2Default = true)
    {
        AssertUtil.NotNull(type);
        if (src.IsNullOrDBNull())
        {
            if (null2Default || !type.IsValueType || type.IsNullable()) return type.GetDefault();
            throw new Exception($"无法从 null or dbnull 转换为 {type.GetClassFullName()}");
        }

        var srcType = src.GetType();
        var destType = type;
        return MapperHelper.Mapper(srcType, destType, src, containsRepeatReference, null2Default);
    }

    ///<summary>
    /// 对象映射，基于同名属性转换原则<br />
    /// 调用方法:
    /// <br />
    /// var person=new Person();<br />
    /// var dto=person.Mapper(typeof(Person),typeof(PersonDto));<br />
    /// var persons=new List&lt;Person>();<br />
    /// var dtos=persons.Mapper(typeof(List&lt;Person>),typeof(List&lt;PersonDto>));<br />
    /// </summary>
    /// <param name="src"></param>
    /// <param name="fromType">源类型</param>
    /// <param name="destType">目标类型</param>
    /// <param name="containsRepeatReference">是否考虑引用关系</param>
    /// <param name="null2Default">是否将null值转换为默认值,而不是抛出异常</param>
    /// <remarks>
    /// 注意：相对于 <c>person.Mapper(typeof(PersonDto))</c> 增加指定源目标类型
    /// </remarks>
    /// <returns></returns>
    public static object Mapper(this object src, Type fromType, Type destType, bool containsRepeatReference = true, bool null2Default = true)
    {
        AssertUtil.NotNull(fromType);
        AssertUtil.NotNull(destType);
        if (src.IsNullOrDBNull())
        {
            if (null2Default || !destType.IsValueType || destType.IsNullable()) return destType.GetDefault();
            throw new Exception($"无法从 null or dbnull 转换为 {destType.GetClassFullName()}");
        }
        return MapperHelper.Mapper(fromType, destType, src, containsRepeatReference, null2Default);
    }
    #endregion

    #region Modify 递归修改指定名称的属性值 object.Modify<T>(propName,obj=>obj)
    /// <summary>
    /// 根据属性名递归修改属性值
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="model"></param>
    /// <param name="propName">属性名</param>
    /// <param name="modifyAction">根据旧值,修改后返回新值</param>
    /// <returns></returns>
    public static T Modify<T>(this T model, string propName, Func<object, object> modifyAction)
    {
        if (model == null) return model;
        _filterDeal(model);
        return model;

        void _filterDeal(object model)
        {
            if (model == null) return;
            var type = model.GetType();
            //这里不接受简单类型
            if (type.IsSimpleType()) return;
            //集合
            if (CollectNames.Any(p => type.FullName.StartsWith(p)))
            {
                var count = (int)type.GetProperties().FirstOrDefault(prop => prop.Name == "Count").GetValue(model);
                if (count == 0)
                {
                    //元素个数为0
                    return;
                }
                else
                {
                    //循环转换
                    var indexProp = type.GetProperty("Item");
                    for (var i = 0; i < count; i++)
                    {
                        var src2 = indexProp.GetValue(model, [i]);
                        _filterDeal(src2);
                    }
                }
            }
            else if (type.IsArray)
            {
                //数组
                var count = (int)type.GetProperties().FirstOrDefault(prop => prop.Name == "Length").GetValue(model);
                if (count == 0)
                {
                    //元素个数为0
                    return;
                }
                else
                {
                    //是集合,且有数据
                    var indexProp = type.GetProperty("Item");
                    foreach (var src2 in model as Array)
                    {
                        _filterDeal(src2);
                    }
                }
            }
            else
            {
                //dto对象
                var props = model.GetType().GetProperties();
                foreach (var prop in props)
                {
                    if (prop.Name == propName && prop.CanWrite)
                    {
                        var old = prop.GetValue(model);
                        try
                        {
                            var newValue = modifyAction(old);
                            prop.SetValue(model, newValue);
                        }
                        catch { }
                    }
                    else
                    {
                        _filterDeal(prop.GetValue(model));
                    }
                }
            }
        }
    }
    #endregion

    #region 使用dto对象改变实体对象上的值 object.ModifyByDto(dto)
    /// <summary>
    /// 将指定dto对象的属性值投影到当前对象（entity）上，改变entity的属性值，基于同名属性反射<br />
    /// 注意：这个方法是为根据dto更新entity提供的，调用此方法时，无论是entity还是dto都不应该是集合，执行主体逻辑如下：
    /// <list type="bullet">
    /// <item>如果dto为null，直接返回entity；</item>
    /// <item>如果dto的类型和entity的类型相同，则直接返回dto对象；</item>
    /// <item>如果entity为null，则新创建一个entity实例，修改后返回新创建的实例；</item>
    /// <item>属性先进行比较，相等则不改变；</item>
    /// <item>对于集合类型，直接覆盖；</item>
    /// <item>对于引用类型，递归修改；</item>
    /// </list>
    /// </summary>
    /// <typeparam name="TResult">目标类型</typeparam>
    /// <param name="dto">dto对象，将这个对象的属性映射到当前对象上，改变当前对象的属性值</param>
    /// <param name="baseObj">基础对象,不能为null</param>
    public static TResult ModifyByDto<TResult>(this TResult baseObj, object dto) where TResult : class
    {
        if (dto == null) return baseObj;
        AssertUtil.NotNull(baseObj);
        return mapperModify(dto, baseObj);
    }

    private static TResult mapperModify<TResult>(object src, TResult baseObj) where TResult : class
    {
        //缓存转换过程，防止循环引用
        var container = new Dictionary<(object src, Type destType), object>();
        TResult dest = baseObj;
        if (dest == null)
        {
            dest = (TResult)Activator.CreateInstance(typeof(TResult));
        }
        container.Add((src, typeof(TResult)), dest);
        return (TResult)mapperModify(src, dest, typeof(TResult), container);
    }

    private static object mapperModify(object src, object dest, Type destType, Dictionary<(object src, Type destType), object> container)
    {
        //null值的转换
        if (src == null || src is DBNull)
        {
            return destType.GetDefault();
        }
        var srcType = src.GetType();
        if (srcType == destType)
        {
            return src;
        }
        #region 集合转换
        //集合转换
        if (CollectNames.Any(p => srcType.FullName.StartsWith(p)) && CollectNames.Any(p => destType.FullName.StartsWith(p)))
        {
            var geneType = destType.GenericTypeArguments[0];
            destType = typeof(List<>).MakeGenericType(geneType);
            if ((int)src.GetType().GetProperties().FirstOrDefault(prop => prop.Name == "Count").GetValue(src) == 0)
            {
                //是集合,但元素个数为0
                var list = Activator.CreateInstance(destType);
                return list;
            }
            else
            {
                //是集合,且有数据
                var list = Activator.CreateInstance(destType);
                //循环转换
                var count = (int)src.GetType().GetProperty("Count").GetValue(src);
                var indexProp = src.GetType().GetProperty("Item");
                for (var i = 0; i < count; i++)
                {
                    var src2 = indexProp.GetValue(src, [i]);
                    //引用类型,递归转
                    object newValue = null;
                    var key = (src2, geneType);
                    if (container.ContainsKey(key))
                    {
                        newValue = container[key];
                    }
                    else
                    {
                        object ele = null;
                        var cons = geneType.GetConstructors().FirstOrDefault(con => con.GetParameters().Length == 0);
                        if (cons != null)
                        {
                            ele = cons.Invoke(Array.Empty<object>());
                        }
                        container.Add((src2, geneType), ele);
                        newValue = mapperModify(src2, ele, geneType, container);
                    }
                    destType.GetMethod("Add").Invoke(list, [newValue]);
                }
                return list;
            }
        }
        //数组转换 和集合转换逻辑一致,代码稍有不同
        if (destType.IsArray && srcType.IsArray)
        {
            var geneType = destType.GetElementType();
            destType = typeof(List<>).MakeGenericType(geneType);
            if ((int)src.GetType().GetProperties().FirstOrDefault(prop => prop.Name == "Length").GetValue(src) == 0)
            {
                //是数组,但元素个数为0
                var list = Activator.CreateInstance(destType);
                return destType.GetMethod("ToArray").Invoke(list, Array.Empty<object>());
            }
            else
            {
                //是集合,且有数据
                var list = Activator.CreateInstance(destType);
                //循环转换
                var indexProp = src.GetType().GetProperty("Item");
                foreach (var src2 in src as Array)
                {
                    object newValue = null;
                    var key = (src2, geneType);
                    if (container.ContainsKey(key))
                    {
                        newValue = container[key];
                    }
                    else
                    {
                        object ele = null;
                        var cons = geneType.GetConstructors().FirstOrDefault(con => con.GetParameters().Length == 0);
                        if (cons != null)
                        {
                            ele = cons.Invoke(Array.Empty<object>());
                        }
                        container.Add((src2, geneType), ele);
                        newValue = mapperModify(src2, ele, geneType, container);
                    }
                    destType.GetMethod("Add").Invoke(list, [newValue]);
                }
                return destType.GetMethod("ToArray").Invoke(list, Array.Empty<object>());
            }
        }
        #endregion
        #region 非集合转换
        var props = src.GetType().GetProperties();
        var props2 = destType.GetProperties();
        foreach (var prop in props)
        {
            var destProp = props2.FirstOrDefault(p => p.Name == prop.Name);
            if (destProp != null)
            {
                //过滤没有set方法的属性
                if (destProp.GetSetMethod() == null) continue;
                var val = prop.GetValue(src);
                var destVal = destProp.GetValue(dest);
                //相等,无需改变值
                if (prop.PropertyType == destProp.PropertyType)
                {
                    try
                    {
                        if (val == null && destProp == null) continue;
                        if (val != null && val.Equals(destVal)) continue;
                    }
                    catch { }
                }

                if (val == null)
                {
                    destProp.SetValue(dest, null);
                    continue;
                }
                if (prop.PropertyType.IsValueType || prop.PropertyType == destProp.PropertyType)
                {
                    //值类型或类型相同直接转
                    destProp.SetValue(dest, val);
                    continue;
                }
                //引用类型,递归转
                object newValue = null;
                var key = (val, destProp.PropertyType);
                if (container.ContainsKey(key))
                {
                    newValue = container[key];
                }
                else
                {
                    object ele = destVal;
                    if (ele == null)
                    {
                        var cons = destProp.PropertyType.GetConstructors().FirstOrDefault(con => con.GetParameters().Length == 0);
                        if (cons != null)
                        {
                            ele = cons.Invoke(Array.Empty<object>());
                        }
                    }
                    container.Add((val, destProp.PropertyType), ele);
                    newValue = mapperModify(val, ele, destProp.PropertyType, container);
                }
                //相等的直接跳过
                if (newValue == val) continue;
                destProp.SetValue(dest, newValue);
            }
        }
        #endregion
        return dest;
    }
    #endregion

    #region DeepClone object.DeepClone()
    /// <summary>
    /// 深度克隆对象实例，支持 <c>简单类poco</c>、<c>数组</c>、<c>List</c>、<c>dicitionary</c>、<c>ValueTuple&lt;></c>、<c>匿名类型</c> 等, 示例代码:
    /// <code>
    /// var list=new List&lt;Person>()
    /// {
    ///     new Person{ Id = 1, Name = "小明" },
    ///     new Person{ Id = 2, Name = "小刚" }
    /// }
    /// var newList = list.DeepClone(false);//因为数据格式简单,没有冗余、循环的引用,传入 false 将克隆缓存关掉以提升性能
    /// </code>
    /// 当实例内部有冗余、循环的引用时:
    /// <code>
    /// var root = new Node { Id = 1, Children = new List&lt;Node>() };
    /// var current = new Node { Id = 2,Parent=root };
    /// root.Children.Add(current);
    /// var newRoot = root.DeepClone(true);//因为数据之间有冗余、循环的引用, 传入 true 打开克隆缓存，引用关系将被一起克隆
    /// </code>
    /// </summary>
    /// <remarks>
    /// 注意：本方法优先使用 <see cref="ICloneable"/> 中的 <c>Clone</c> 方法
    /// </remarks>
    /// <typeparam name="T"></typeparam>
    /// <param name="obj"></param>
    /// <param name="containsRepeatReference">是否考虑重复的引用,当要克隆的对象内部没有冗余的、循环的引用时,将此设为 <c>false</c> 可能提升一半性能</param>
    /// <param name="capacity">当 <c>containsRepeatReference</c> 设为true时,缓存字典的默认容量</param>
    /// <returns></returns>
    public static T DeepClone<T>(this T obj, bool containsRepeatReference = true)
        => DeepCloneHelper.DeepColne(obj, containsRepeatReference);
    #endregion

    private static readonly List<string> CollectNames =
    [
        "System.Collections.Generic.List`1",
        "System.Collections.Generic.IList`1",
        "System.Collections.Generic.IEnumerable`1",
        "System.Collections.Generic.ICollection`1"
    ];

    #region ToJson & ToJsonFast
    //Newtonsoft.Json.JsonConvert.SerializeObject(object)
    private static Func<object, string> _getNewtonsoftJsonSerialize = null;
    internal static Func<object, string> GetNewtonsoftJsonSerialize(Assembly assembly)
    {
        if (_getNewtonsoftJsonSerialize == null)
        {
            var tmp = assembly.GetType("Newtonsoft.Json.JsonConvert");
            var method = tmp.GetMethods().FirstOrDefault(i => i.Name == "SerializeObject" && i.GetParameters().Length == 1);
            var para = Expression.Parameter(typeof(object), "obj");
            _getNewtonsoftJsonSerialize = Expression.Lambda<Func<object, string>>(Expression.Call(null, method, [para]), para).Compile();
        }
        return _getNewtonsoftJsonSerialize;
    }

    //Newtonsoft.Json.JsonConvert.SerializeObject(object,Newtonsoft.Json.JsonSerializerSettings)
    private static Func<object, string, bool, bool, bool, bool, string> _getNewtonsoftJsonSerialize2 = null;
    /// <summary>
    /// 其实 JObject/JArray 转 json, 也就 isIntend 生效
    /// </summary>
    /// <param name="assembly"></param>
    /// <returns></returns>
    internal static Func<object, string, bool, bool, bool, bool, string> GetNewtonsoftJsonSerialize2(Assembly assembly)
    {
        if (_getNewtonsoftJsonSerialize2 == null)
        {
            var tmp = assembly.GetType("Newtonsoft.Json.JsonConvert");
            var tmp2 = assembly.GetType("Newtonsoft.Json.JsonSerializerSettings");
            var method = tmp.GetMethods().FirstOrDefault(i => i.Name == "SerializeObject" && i.GetParameters().Length == 2 && i.GetParameters().LastOrDefault().ParameterType == tmp2);
            var para = Expression.Parameter(typeof(object), "obj");
            var para_DateFormatString = Expression.Parameter(typeof(string), "DateFormatString");
            var para_NullValueHandling = Expression.Parameter(typeof(bool), "NullValueHandling");
            var para_StringEnumConverter = Expression.Parameter(typeof(bool), "StringEnumConverter");
            var para_ContractResolver = Expression.Parameter(typeof(bool), "ContractResolver");
            var para_Formatting = Expression.Parameter(typeof(bool), "Formatting");

            var local_settings = Expression.Variable(tmp2, "settings");
            var tmp3 = assembly.GetType("Newtonsoft.Json.NullValueHandling");
            var tmp4 = assembly.GetType("Newtonsoft.Json.Converters.StringEnumConverter");
            var tmp5 = assembly.GetType("Newtonsoft.Json.JsonConverter");
            var tmp6 = assembly.GetType("Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver");
            var tmp7 = assembly.GetType("Newtonsoft.Json.Formatting");

            var assign_local = Expression.Assign(local_settings, Expression.New(tmp2.GetConstructor(Array.Empty<Type>())));
            var assign_DateFormatString = Expression.IfThen(Expression.NotEqual(para_DateFormatString, Expression.Constant(null)), Expression.Assign(Expression.MakeMemberAccess(local_settings, tmp2.GetProperty("DateFormatString")), para_DateFormatString));
            var assign_NullValueHandling = Expression.IfThen(Expression.Equal(para_NullValueHandling, Expression.Constant(true)), Expression.Assign(Expression.MakeMemberAccess(local_settings, tmp2.GetProperty("NullValueHandling")), Expression.Convert(Expression.Constant(1), tmp3)));

            //var addMethod = typeof(List<>).MakeGenericType(tmp5).GetMethod("Add");
            var addMethod = typeof(ICollection<>).MakeGenericType(tmp5).GetMethod("Add");
            var assign_StringEnumConverter = Expression.IfThen(Expression.Equal(para_StringEnumConverter, Expression.Constant(true)), Expression.Call(Expression.Property(local_settings, "Converters"), addMethod, Expression.New(tmp4)));
            var assign_ContractResolver = Expression.IfThen(Expression.Equal(para_ContractResolver, Expression.Constant(true)), Expression.Assign(Expression.Property(local_settings, "ContractResolver"), Expression.New(tmp6.GetConstructor(Array.Empty<Type>()))));
            var assign_Formatting = Expression.IfThen(Expression.Equal(para_Formatting, Expression.Constant(true)), Expression.Assign(Expression.Property(local_settings, "Formatting"), Expression.Convert(Expression.Constant(1), tmp7)));

            var finalCall = Expression.Call(null, method, para, local_settings);

            _getNewtonsoftJsonSerialize2 = Expression.Lambda<Func<object, string, bool, bool, bool, bool, string>>(Expression.Block([local_settings],
                assign_local,
                assign_DateFormatString,
                assign_NullValueHandling,
                assign_StringEnumConverter,
                assign_ContractResolver,
                assign_Formatting,
                finalCall)
                , para, para_DateFormatString, para_NullValueHandling, para_StringEnumConverter, para_ContractResolver, para_Formatting
                ).Compile();
        }
        return _getNewtonsoftJsonSerialize2;
    }

    //Newtonsoft.Json.Linq.JValue.ToObject(Type)
    private static Func<object, Type, object> _getNewtonsoftJsonSerialize3 = null;
    /// <summary>
    /// 用于, 元类型无法通过常规序列化反序列化转化时
    /// <code>
    /// var obj = Newtonsoft.Json.JsonConvert.DeserializeObject&lt;JObject>("{\"Time\":\"2024-02-01 12:02:03\"}");
    /// obj["Time"].ToObject(typeof(DateTime))
    /// </code>
    /// </summary>
    /// <param name="assembly"></param>
    /// <returns></returns>
    private static Func<object, Type, object> getNewtonsoftJsonSerialize3(Assembly assembly)
    {
        if (_getNewtonsoftJsonSerialize3 == null)
        {
            var tmp = assembly.GetType("Newtonsoft.Json.Linq.JValue");
            var method = tmp.GetMethods().FirstOrDefault(i => i.Name == "ToObject" && i.GetParameters().Length == 1 && i.GetParameters().First().ParameterType == typeof(Type));
            var para = Expression.Parameter(typeof(object), "obj");
            var para2 = Expression.Parameter(typeof(Type), "type");
            var finalCall = Expression.Call(Expression.Convert(para, tmp), method, para2);

            _getNewtonsoftJsonSerialize3 = Expression.Lambda<Func<object, Type, object>>(finalCall, para, para2).Compile();
        }
        return _getNewtonsoftJsonSerialize3;
    }

    /// <summary>
    /// 序列化为json字符串, 默认使用 <c>System.Text.Json</c>
    /// </summary>
    /// <remarks>
    /// 注意: 
    /// <list type="bullet">
    /// <item>aot 模式下将改用 NewtonSoft, 此时传入的 <c>options</c> 将会被忽略</item>
    /// <item>aot 模式下需要先自行在项目中引用 NewtonSoft.Json.dll 因为 DotNetCommon 本身不直接引用它, 但是会用反射加载它</item>
    /// </list>
    /// </remarks>
    public static string ToJson(this object obj, JsonSerializerOptions options)
    {
        if (obj == null) return null;

        if (Machine.IsRunningInAotMode())
        {
            #region aot模式
            if (obj is JsonNode jsonNode) return jsonNode.ToJsonString(options);
            if (obj is JsonDocument jsonDoc) return JsonNode.Parse(jsonDoc.RootElement.GetRawText()).ToJsonString(options);
            if (obj is JsonTreeNode node) return node.BuildJsonNode().ToJsonString(options);
            Func<object, string> act;
            if (_getNewtonsoftJsonSerialize != null)
            {
                act = _getNewtonsoftJsonSerialize;
            }
            else
            {
                try
                {
                    var type = Type.GetType("Newtonsoft.Json.JsonConvert, Newtonsoft.Json");
                    act = GetNewtonsoftJsonSerialize(type.Assembly);
                }
                catch (Exception e)
                {
                    throw new Exception($"在aot模式下 object.ToJson() 需要改用 NewtonSoft.Json, 但加载失败, 请自行在项目中引用 NewtonSoft.Json 程序集", e);
                }
            }
            return act(obj);
            #endregion
        }
        else
        {
            //兼容 JObject 和 JArray
            var fullName = obj.GetType().FullName;
            if (fullName == "Newtonsoft.Json.Linq.JObject" || fullName == "Newtonsoft.Json.Linq.JArray")
            {
                return GetNewtonsoftJsonSerialize(obj.GetType().Assembly)(obj);
            }

            //使用 System.Text.Json
            if (obj is JsonTreeNode node) return node.BuildJsonNode().ToJsonString(options);
            return JsonSerializer.Serialize(obj, options);
        }
    }

    /// <summary>
    /// aot模式下基础设置
    /// </summary>
    private static readonly JsonSerializerOptions aotOptions = new()
    {
        Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
    };
    private static readonly JsonSerializerOptions aotOptionsIntend = new()
    {
        Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
        WriteIndented = true,
    };

    /// <summary>
    /// 序列化为json字符串, 默认使用 <c>System.Text.Json</c>
    /// </summary>
    /// <remarks>
    /// 注意: 
    /// <list type="bullet">
    /// <item>aot 模式下需要先自行在项目中引用 NewtonSoft.Json.dll 因为 DotNetCommon 本身不直接引用它, 但是会用反射加载它</item>
    /// </list>
    /// </remarks>
    public static string ToJson(this object obj)
    {
        if (obj == null) return null;

        if (Machine.IsRunningInAotMode())
        {
            #region aot模式
            if (obj is JsonNode jsonNode) return jsonNode.ToJsonString(aotOptions);
            if (obj is JsonDocument jsonDoc) return JsonNode.Parse(jsonDoc.RootElement.GetRawText()).ToJsonString(aotOptions);
            if (obj is JsonTreeNode node) return node.BuildJsonNode().ToJsonString(aotOptions);
            Func<object, string> act;
            if (_getNewtonsoftJsonSerialize != null)
            {
                act = _getNewtonsoftJsonSerialize;
            }
            else
            {
                try
                {
                    var type = Type.GetType("Newtonsoft.Json.JsonConvert, Newtonsoft.Json");
                    act = GetNewtonsoftJsonSerialize(type.Assembly);
                }
                catch (Exception e)
                {
                    throw new Exception($"在aot模式下 object.ToJson() 需要改用 NewtonSoft.Json, 但加载失败, 请自行在项目中引用 NewtonSoft.Json 程序集", e);
                }
            }
            return act(obj);
            #endregion
        }
        else
        {
            //兼容 JObject 和 JArray
            var fullName = obj.GetType().FullName;
            if (fullName == "Newtonsoft.Json.Linq.JObject" || fullName == "Newtonsoft.Json.Linq.JArray")
            {
                return GetNewtonsoftJsonSerialize(obj.GetType().Assembly)(obj);
            }

            //使用 System.Text.Json
            var options = JsonHelper._getDefaultJsonSerializerOptions(readOnly: true);
            if (obj is JsonTreeNode node) return node.BuildJsonNode().ToJsonString(options);
            return JsonSerializer.Serialize(obj, options);
        }
    }

    /// <summary>
    /// 序列化为json字符串, 默认使用 <c>System.Text.Json</c>
    /// </summary>
    /// <remarks>
    /// 注意: 
    /// <list type="bullet">
    /// <item>aot 模式下将改用 NewtonSoft, 此时传入的 <c>otherSettings</c> 将会被忽略</item>
    /// <item>aot 模式下需要先自行在项目中引用 NewtonSoft.Json.dll 因为 DotNetCommon 本身不直接引用它, 但是会用反射加载它</item>
    /// </list>
    /// </remarks>
    public static string ToJson(this object obj, Action<JsonSerializerOptions> otherSettings)
    {
        if (obj == null) return null;

        if (Machine.IsRunningInAotMode())
        {
            #region aot模式
            JsonSerializerOptions getOptions()
            {
                var opt = otherSettings == null ? aotOptions : new JsonSerializerOptions
                {
                    Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
                };
                otherSettings?.Invoke(opt);
                return opt;
            }

            if (obj is JsonNode jsonNode) return jsonNode.ToJsonString(getOptions());
            if (obj is JsonDocument jsonDoc) return JsonNode.Parse(jsonDoc.RootElement.GetRawText()).ToJsonString(getOptions());
            if (obj is JsonTreeNode node) return node.BuildJsonNode().ToJsonString(getOptions());
            Func<object, string> act;
            if (_getNewtonsoftJsonSerialize != null)
            {
                act = _getNewtonsoftJsonSerialize;
            }
            else
            {
                try
                {
                    var type = Type.GetType("Newtonsoft.Json.JsonConvert, Newtonsoft.Json");
                    act = GetNewtonsoftJsonSerialize(type.Assembly);
                }
                catch (Exception e)
                {
                    throw new Exception($"在aot模式下 object.ToJson() 需要改用 NewtonSoft.Json, 但加载失败, 请自行在项目中引用 NewtonSoft.Json 程序集", e);
                }
            }
            return act(obj);
            #endregion
        }
        else
        {
            //兼容 JObject 和 JArray
            var fullName = obj.GetType().FullName;
            if (fullName == "Newtonsoft.Json.Linq.JObject" || fullName == "Newtonsoft.Json.Linq.JArray")
            {
                return GetNewtonsoftJsonSerialize(obj.GetType().Assembly)(obj);
            }

            //使用 System.Text.Json
            var options = JsonHelper._getDefaultJsonSerializerOptions(readOnly: otherSettings == null);
            otherSettings?.Invoke(options);
            if (obj is JsonTreeNode node) return node.BuildJsonNode().ToJsonString(options);
            return JsonSerializer.Serialize(obj, options);
        }
    }

    /// <summary>
    /// 快速将对象转换为 <c>JsonObject</c><br/>
    /// 实际上是 <c> obj.ToJson().ToObject&lt;JsonObject>() </c> 的简写
    /// </summary>
    /// <remarks>
    /// 注意: 
    /// <list type="bullet">
    /// <item>aot 模式下需要先自行在项目中引用 NewtonSoft.Json.dll 因为 DotNetCommon 本身不直接引用它, 但是会用反射加载它</item>
    /// </list>
    /// </remarks>
    public static JsonObject ToJsonObject(this object obj)
    {
        if (obj is JsonObject jsonObject) return jsonObject;
        if (obj is null) return null;
        return JsonObject.Parse(obj.ToJson()).AsObject();
    }

    /// <summary>
    /// 快速将对象转换为 <c>JsonArray</c><br/>
    /// 实际上是 <c> obj.ToJson().ToObject&lt;JsonArray>() </c> 的简写
    /// </summary>
    /// <remarks>
    /// 注意: 
    /// <list type="bullet">
    /// <item>aot 模式下需要先自行在项目中引用 NewtonSoft.Json.dll 因为 DotNetCommon 本身不直接引用它, 但是会用反射加载它</item>
    /// </list>
    /// </remarks>
    public static JsonArray ToJsonArray(this object obj)
    {
        if (obj is JsonArray jsonArray) return jsonArray;
        if (obj is null) return null;
        return JsonArray.Parse(obj.ToJson()).AsArray();
    }

    /// <summary>
    /// 快速将对象转换为 <c>JsonNode</c><br/>
    /// 实际上是 <c> obj.ToJson().ToObject&lt;JsonNode>() </c> 的简写
    /// </summary>
    /// <remarks>
    /// 注意: 
    /// <list type="bullet">
    /// <item>aot 模式下需要先自行在项目中引用 NewtonSoft.Json.dll 因为 DotNetCommon 本身不直接引用它, 但是会用反射加载它</item>
    /// </list>
    /// </remarks>
    public static JsonNode ToJsonNode(this object obj)
    {
        if (obj is JsonNode jsonNode) return jsonNode;
        if (obj is null) return null;
        return JsonNode.Parse(obj.ToJson());
    }

    /// <summary>
    /// 指定常用的设置,序列化为json字符串, 默认使用 <c>System.Text.Json</c>
    /// </summary>
    /// <param name="obj"></param>
    /// <param name="dateTimeFormatString">日期时间格式(DateTime)</param>
    /// <param name="dateTimeOffsetFormatString">日期时间格式(DateTimeOffset)</param>
    /// <param name="dateOnlyFormatString">日期时间格式(DateOnly)</param>
    /// <param name="timeOnlyFormatString">日期时间格式(TimeOnly)</param>
    /// <param name="ignoreNull">是否忽略null值的属性</param>
    /// <param name="enum2String">是否将枚举转换为字符串</param>
    /// <param name="lowerCamelCase">属性名称的首字母是否小写</param>
    /// <param name="lowerCamelCaseDictionaryKey">字典key首字母是否小写</param>
    /// <param name="isIntend">是否格式缩进</param>
    /// <param name="number2String">是否将数字转为字符串</param>
    /// <param name="ignoreJsonPropertyName">是否忽略注解: [JsonPropertyName("xxxx")]</param>
    /// <param name="otherSettings">其他的设置</param>
    /// <remarks>
    /// 注意: 
    /// <list type="bullet">
    /// <item>aot 模式下需要先自行在项目中引用 NewtonSoft.Json.dll 因为 DotNetCommon 本身不直接引用它, 但是会用反射加载它</item>
    /// <item>虽然提供了 <c>lowerCamelCase</c> 和 <c>lowerCamelCaseDictionaryKey</c>, 但没有办法将 <c>JsonObject</c> 中的key首字母小写</item>
    /// </list>
    /// </remarks>
    public static string ToJsonFast(this object obj,
        string dateTimeFormatString = null,
        string dateTimeOffsetFormatString = null,
        string dateOnlyFormatString = null,
        string timeOnlyFormatString = null,
        bool ignoreNull = false,
        bool enum2String = false,
        bool lowerCamelCase = false,
        bool lowerCamelCaseDictionaryKey = false,
        bool isIntend = false,
        bool number2String = false,
        bool ignoreJsonPropertyName = false,
        Action<JsonSerializerOptions> otherSettings = null)
    {
        if (obj == null) return null;

        //aot模式下自适应
        if (Machine.IsRunningInAotMode())
        {
            #region aot模式
            JsonSerializerOptions getOptions()
            {
                var opt = otherSettings == null ? (isIntend ? aotOptionsIntend : aotOptions) : new JsonSerializerOptions
                {
                    Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
                };
                otherSettings?.Invoke(opt);
                return opt;
            }
            if (obj is JsonNode jsonNode) return jsonNode.ToJsonString(getOptions());
            if (obj is JsonDocument jsonDoc) return JsonNode.Parse(jsonDoc.RootElement.GetRawText()).ToJsonString(getOptions());
            if (obj is JsonTreeNode node) return node.BuildJsonNode().ToJsonString(getOptions());

            Func<object, string, bool, bool, bool, bool, string> act;
            if (_getNewtonsoftJsonSerialize2 != null)
            {
                act = _getNewtonsoftJsonSerialize2;
            }
            else
            {
                try
                {
                    var type = Type.GetType("Newtonsoft.Json.JsonConvert, Newtonsoft.Json");
                    act = GetNewtonsoftJsonSerialize2(type.Assembly);
                }
                catch (Exception e)
                {
                    throw new Exception($"在aot模式下 ToJsonFast 需要改用 NewtonSoft.Json, 但加载失败, 请自行在项目中引用 NewtonSoft.Json 程序集", e);
                }
            }
            return act(obj, dateTimeFormatString, ignoreNull, enum2String, lowerCamelCase, isIntend);
            #endregion
        }
        else
        {
            //兼容 JObject 和 JArray
            var fullName = obj.GetType().FullName;
            if (fullName == "Newtonsoft.Json.Linq.JObject" || fullName == "Newtonsoft.Json.Linq.JArray")
            {
                return GetNewtonsoftJsonSerialize2(obj.GetType().Assembly)(obj, dateTimeFormatString, ignoreNull, enum2String, lowerCamelCase, isIntend);
            }

            //使用 System.Text.Json
            var options = JsonHelper._getDefaultJsonSerializerOptions(
                dateTimeFormatString: dateTimeFormatString,
                dateTimeOffsetFormatString: dateTimeOffsetFormatString,
                dateOnlyFormatString: dateOnlyFormatString,
                timeOnlyFormatString: timeOnlyFormatString,
                ignoreNull: ignoreNull,
                enum2String: enum2String,
                lowerCamelCase: lowerCamelCase,
                lowerCamelCaseDictionaryKey: lowerCamelCaseDictionaryKey,
                isIntend: isIntend,
                number2String: number2String,
                ignoreJsonPropertyName: ignoreJsonPropertyName,
                readOnly: otherSettings == null);
            otherSettings?.Invoke(options);

            if (obj is JsonTreeNode node) return node.BuildJsonNode().ToJsonString(options);
            return JsonSerializer.Serialize(obj, options);
        }
    }
    #endregion

    /// <summary>
    /// 是否是数字类型
    /// </summary>
    /// <param name="obj"></param>
    /// <returns></returns>
    public static bool IsNumeric(this object obj)
    {
        if (obj == null) return false;
        return obj.GetType().IsNumeric();
    }

    /// <summary>
    /// 是否是枚举类型
    /// </summary>
    /// <param name="obj"></param>
    /// <returns></returns>
    public static bool IsEnum(this object obj)
    {
        if (obj == null) return false;
        return obj.GetType().IsEnum;
    }

    /// <summary>
    /// obj is null || obj is DBNull
    /// </summary>
    /// <param name="obj"></param>
    /// <returns></returns>
    public static bool IsNullOrDBNull(this object obj) => obj is null || obj is DBNull;

    #region ToDictionary
    /// <summary>
    /// 将当前对象转成字典(属性名->属性值)
    /// </summary>
    /// <param name="object">原对象</param>
    /// <param name="includePrivate">是否包含私有属性，即: private string name { set; get; }</param>
    /// <param name="inherit">是否包含继承的属性</param>
    public static Dictionary<string, object> ToDictionary(this object @object, bool inherit = true, bool includePrivate = false)
    {
        var dic = new Dictionary<string, object>();
        if (@object == null) return dic;
        foreach (var property in @object.GetType().GetInstanceProperties(inherit, includePrivate))
        {
            dic.Add(property.Name, property.GetValue(@object));
        }
        return dic;
    }

    /// <summary>
    /// 将当前对象转成字典(属性名->属性值) <br />
    /// 注意: 相对于 <seealso cref="ToDictionary(object, bool, bool)"/> 这个只会返回属性值为 <c>T</c> 或 <c>T?</c> 类型的字典, 如果属性值不是 <c>T</c> 或 <c>T?</c> 类型, 将被忽略
    /// </summary>
    /// <param name="object">原对象</param>
    /// <param name="includePrivate">是否包含私有属性，即: private string name { set; get; }</param>
    /// <param name="inherit">是否包含继承的属性</param>
    public static Dictionary<string, TValue> ToDictionary<TValue>(this object @object, bool inherit = true, bool includePrivate = false)
    {
        var dic = new Dictionary<string, TValue>();
        if (@object == null) return dic;
        foreach (var property in @object.GetType().GetInstanceProperties(inherit, includePrivate))
        {
            if (typeof(TValue).IsParentOrAssignableFrom(property.PropertyType))
            {
                dic.Add(property.Name, (TValue)property.GetValue(@object));
            }
        }
        return dic;
    }
    #endregion
}

/// <summary>
/// 类转换时的参数
/// </summary>
/// <remarks>
/// 构造函数
/// </remarks>
/// <param name="args"></param>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
public class MapperArgumentsAttribute(params object[] args) : Attribute
{
    /// <summary>
    /// 参数数组
    /// </summary>
    public object[] Args { get; } = args;
}
